// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:build ignore 

// 生成Windows回调程序集文件。

package main

import (
	"bytes"
	"fmt"
	"os"
)

const maxCallback = 2000

func genasm386Amd64() {
	var buf bytes.Buffer

	buf.WriteString(`// wincallback生成的代码。使用“go generate”开始。不要编辑。

// go:build 386 | | amd64 

// runtime·callbackasm由外部代码调用
// 执行go实现的回调函数。它不是从一开始就调用的
// 而是runtime·compilecallback 
// 始终将地址返回到runtime·callbackasm offset 
// 因此，不同的回调从不同的
// runtime·callbackasm中的调用指令开始。这决定了后面将执行哪个Go回调函数。

TEXT runtime·callbackasm(SB),7,$0
`)
	for i := 0; i < maxCallback; i++ {
		buf.WriteString("\tCALL\truntime·callbackasm1(SB)\n")
	}

	filename := fmt.Sprintf("zcallback_windows.s")
	err := os.WriteFile(filename, buf.Bytes(), 0666)
	if err != nil {
		fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
		os.Exit(2)
	}
}

func genasmArm() {
	var buf bytes.Buffer

	buf.WriteString(`// wincallback生成的代码。使用“go generate”开始。不要编辑。

// 外部代码在回调索引对应的偏移量处调用callbackasm。Callbackasm是MOV和B指令表。
// MOV指令用回调索引加载R12，
// B指令分支到回调ASM1。
// callbackasm1将R12和
// 索引中的回调索引放入一个数组，该数组存储有关每个回调的信息。
// 然后调用该回调的Go实现。
#include "textflag.h"

TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0
`)
	for i := 0; i < maxCallback; i++ {
		buf.WriteString(fmt.Sprintf("\tMOVW\t$%d, R12\n", i))
		buf.WriteString("\tB\truntime·callbackasm1(SB)\n")
	}

	err := os.WriteFile("zcallback_windows_arm.s", buf.Bytes(), 0666)
	if err != nil {
		fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
		os.Exit(2)
	}
}

func genasmArm64() {
	var buf bytes.Buffer

	buf.WriteString(`// wincallback生成的代码。使用“go generate”开始。不要编辑。

// 外部代码在回调索引对应的偏移量处调用callbackasm。Callbackasm是MOV和B指令表。
// MOV指令用回调索引加载R12，
// B指令分支到回调ASM1。
// callbackasm1将R12和
// 索引中的回调索引放入一个数组，该数组存储有关每个回调的信息。
// 然后调用该回调的Go实现。
#include "textflag.h"

TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0
`)
	for i := 0; i < maxCallback; i++ {
		buf.WriteString(fmt.Sprintf("\tMOVD\t$%d, R12\n", i))
		buf.WriteString("\tB\truntime·callbackasm1(SB)\n")
	}

	err := os.WriteFile("zcallback_windows_arm64.s", buf.Bytes(), 0666)
	if err != nil {
		fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
		os.Exit(2)
	}
}

func gengo() {
	var buf bytes.Buffer

	buf.WriteString(fmt.Sprintf(`// wincallback生成的代码。使用“go generate”开始。不要编辑。

package runtime

const cb_max = %d // 允许的最大windows回调数
`, maxCallback))
	err := os.WriteFile("zcallback_windows.go", buf.Bytes(), 0666)
	if err != nil {
		fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
		os.Exit(2)
	}
}

func main() {
	genasm386Amd64()
	genasmArm()
	genasmArm64()
	gengo()
}
